package com.etlmaster.executor.parser;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.etlmaster.executor.EtlMasterException;
import com.etlmaster.executor.Job;
import com.etlmaster.executor.JobMeta;
import com.etlmaster.executor.JobPool;
import com.etlmaster.executor.StepMeta;
import com.etlmaster.executor.boot.PluginJarLoader;
import com.etlmaster.executor.utils.DataCollectionUtils;
import com.etlmaster.executor.utils.DpExecutorUtils;
import com.etlmaster.executor.utils.JsonHelper;
import com.etlmaster.executor.utils.LogWriter;
import com.etlmaster.executor.utils.ScanPackage;
import com.etlmaster.executor.utils.XmlParser;
import com.etlmaster.jdbc.JdbcTemplate;

public class JobBuilder {

	public static Map<String, String> STEP_INST_CLASS_MAPP = new HashMap<String, String>();

	static {
		PluginJarLoader.loadJar(DataCollectionUtils.getProperties("steps_path"));
		ScanPackage.autoScanStepInstruction( DataCollectionUtils.getProperties("basepkg"), false, STEP_INST_CLASS_MAPP);
		ScanPackage.autoScanStepInstruction(DataCollectionUtils.getProperties("pluginPkg"), true, STEP_INST_CLASS_MAPP);
	}


	protected static Job build(String id, Map<String, Object> params,
			XmlJobParser parser, Job job) {
		String logFile = (String) params.get("logFile");
		String isDebug = (String) params.get("isDebug");

		if (job == null) {
			job = parseXml(parser.load(id, params), true, logFile, isDebug);
			JobPool.addToVariableList(job.getMeta().getSeesionId(), params);
			if (params != null && params.size() > 0) {
				job.addVariables(job.getMeta().getSeesionId(), params);
			}
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhMMss");
			String currentDate = sdf.format(System.currentTimeMillis());
			job.putVariable("current_date", currentDate);
			if (job.getVariable("taskid") == null) {
				job.putVariable("taskid", currentDate.substring(0, 8));
			}
			job.putVariable("job_name", job.getMeta().getName());
			initDatabaseParameters(id, job);

			JobPool.regist(job);

		} else {

			if (params != null && params.size() > 0) {
				JobPool.addToVariableList(job.getMeta().getSeesionId(), params);
				job.addVariables(job.getMeta().getSeesionId(), params);

			}
		}
		return job;
	}

	/**
	 * 解析节点
	 * 
	 * @param taskXml
	 * @param meta
	 * @return
	 */
	private static Job parseXml(XmlJob xmlJob, boolean useConfigTable,
			String fileLog, String isDebug) {
		JobMeta jobMeta = new JobMeta(xmlJob.jobId, xmlJob.jobId,
				xmlJob.jobBatchNo, xmlJob.teamCode, fileLog, isDebug);
		// jobMeta.setJobBatchNo(jobMeta.get);
		Job job = new Job(jobMeta);
		if (xmlJob.variables != null) {
			try {
				Map<String, Object> attachVars = (Map<String, Object>) JsonHelper
						.getInstance().read(xmlJob.variables);
				job.addVariables(job.getMeta().getSeesionId(), attachVars);
			} catch (Exception e) {
				LogWriter.addLog("WARN", "varStr {} is not validate",
						xmlJob.variables);
			}
		}

		// 第一次循环初始化所有的stepMeta 不包含pre next
		for (int i = 0; i < xmlJob.step.size(); i++) {
			XmlStep stepXml = xmlJob.step.get(i);
			StepMeta curStepMeta = transXmlToMeta(stepXml, jobMeta);
			curStepMeta.setUseConfigTable(useConfigTable);
			job.getStepMetaIndexs().put(curStepMeta.getId(), curStepMeta);

			// 初始化pre与complete
			if (stepXml.nextSteps != null && stepXml.nextSteps.length() > 0
					&& !stepXml.nextSteps.equals("-1")) {
				String[] nextStepIds = stepXml.nextSteps.split(",");
				for (int j = 0; j < nextStepIds.length; j++) {
					if (!job.getNextStepIndex()
							.containsKey(curStepMeta.getId())) {
						job.getNextStepIndex().put(curStepMeta.getId(),
								new ArrayList<String>());
					}
					job.getNextStepIndex().get(curStepMeta.getId())
							.add(nextStepIds[j]);

					if (!job.getPreStepIndex().containsKey(nextStepIds[j])) {
						job.getPreStepIndex().put(nextStepIds[j],
								new ArrayList<String>());
					}
					job.getPreStepIndex().get(nextStepIds[j])
							.add(curStepMeta.getId());
				}
			}

			String sucessStep = stepXml.successSteps;
			if (sucessStep != null) {

				if (!job.getSuccessStepIndex().containsKey(
						(curStepMeta.getId()))) {
					job.getSuccessStepIndex().put(curStepMeta.getId(),
							new ArrayList<String>());
				}
				job.getSuccessStepIndex().get(curStepMeta.getId())
						.add(sucessStep);
			}

			String failedStep = stepXml.failedSteps;

			if (failedStep != null) {
				if (!job.getFailedStepIndex().containsKey(curStepMeta.getId())) {
					job.getFailedStepIndex().put(curStepMeta.getId(),
							new ArrayList<String>());
				}
				job.getFailedStepIndex().get(curStepMeta.getId())
						.add(failedStep);
			}

			String completeStep = stepXml.completeSteps;

			if (completeStep != null) {
				if (!job.getCompleteStepIndex()
						.containsKey(curStepMeta.getId())) {
					job.getCompleteStepIndex().put(curStepMeta.getId(),
							new ArrayList<String>());
				}
				job.getCompleteStepIndex().get(curStepMeta.getId())
						.add(completeStep);
			}

		}

		return job;
	}

	private static StepMeta transXmlToMeta(XmlStep stepXml, JobMeta jobMeta) {
		String className = JobBuilder.STEP_INST_CLASS_MAPP
				.get(stepXml.stepInst);
		StepMeta stepMeta = null;
		if (className == null) {
			LogWriter.addLog(jobMeta.getId(),0,"ERROR", "步骤指令[{}]错误，程序执行中止", stepXml.stepInst);
			throw new EtlMasterException("步骤指令[" + stepXml.stepInst
					+ "]错误，程序执行中止");
		} else {
			try {
				Class cls = Class.forName(className);
				Constructor<StepMeta> constructor = cls.getConstructor(
						String.class, String.class, String.class,
						String.class, String.class);
				stepMeta = constructor.newInstance(stepXml.id, stepXml.name,
						stepXml.stepInst, jobMeta.getSeesionId(), stepXml.value);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
		return stepMeta;
	}

	@SuppressWarnings("unchecked")
	private static void initDatabaseParameters(String jobId, final Job job) {
		Map<String, Object> dbParams = new HashMap<String, Object>();
		List varList=null;
		if (jobId != null && !jobId.contains(".xml")) {
			String sql = DataCollectionUtils.getProperties("fetchGlobalVal");
			try {
				varList = getJdbcTemplate().queryForList(sql);
				
			} catch (Exception e) {
				LogWriter.addLog(job.getMeta().getId(),0,"ERROR", "从数据库表[proc_global_val]加载配置参数不成功",
						e.getMessage());
			}
		} else if (jobId != null && jobId.contains(".xml")) {

			varList=XmlParser.parseXMLUtils(jobId,"val");
			
		}
		dbParams = parseVals(varList, job);
		JobPool.setInitVariable(dbParams);
	}

	private static Map<String, Object> parseVals(List valList, final Job job) {
		Map<String, Object> dbParams = new HashMap<String, Object>();
		for (int i = 0; i < valList.size(); i++) {
			Map<String, String> valEntry = (Map<String, String>) valList.get(i);
			String varName = valEntry.get("var_name");
			String sqlStatement = valEntry.get("sql_def");
			String value = sqlStatement;

			if (sqlStatement.toLowerCase().indexOf("select") != -1) {
				String sql = DpExecutorUtils.variableSubstitution(sqlStatement,
						job.getVariables());
				value = getJdbcTemplate().queryForObject(sql, String.class);
			} else {
				value = DpExecutorUtils.variableSubstitution(sqlStatement,
						job.getVariables());
			}
			job.putVariable(varName, value);
			dbParams.put(varName, value);
		}
		return dbParams;
	}

	private static JdbcTemplate getJdbcTemplate() {
		return new JdbcTemplate();
	}
}
